﻿/*
 * Created by SharpDevelop.
 * User: ratul
 * Date: 3/6/2010
 * Time: 12:08 AM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;

namespace H264Impl.NET.Coding
{
	/// <summary>
	/// Description of ExpGolomb.
	/// </summary>
	public static class ExpGolomb
	{
//		public ExpGolomb()
//		{
//		}
		
		public static UInt32 getMappedElement(BitStream bitStream, UInt32 chromaArrayType, Macroblock.MacroblockPartitionPredictionMode macroblockPartitionPredictionMode)           //me(v) 
		{
			UInt32 result = getUnsignedIntegerElement(bitStream);
			return mapToCodedBlockPatternValue(result, chromaArrayType, macroblockPartitionPredictionMode);
		}
		
		public static Int32 getSignedIntegerElement(BitStream bitStream)     //se(v)
		{
			UInt32 result = getUnsignedIntegerElement(bitStream);
			return (Int32)(Math.Pow(-1, (double)(result+1)) * Math.Ceiling((double)(result)/2.0));
		}
		
		public static UInt32 getTruncatedElement(BitStream bitStream, UInt32 maxRange)        //te(v)
		{
			if(maxRange>1)
				return getUnsignedIntegerElement(bitStream);
			else if (maxRange==1)
			{
				bool result = bitStream.getBit();
				if(result==true)
					return 0;
				else return 1;
			}
			else
				throw new ArgumentOutOfRangeException();
		}
		
		public static UInt32 getUnsignedIntegerElement(BitStream bitStream)  //ue(v)
		{
			UInt16 leadingZeroBits = 0;
			bool b;	
			for( b = bitStream.getBit(); b!=true;  b = bitStream.getBit() )
				leadingZeroBits++;
			
			return (UInt32)((Math.Pow(2.0, (double)(leadingZeroBits)))) + bitStream.getBits(leadingZeroBits) -1;
			
		}
		
		
		private static UInt32 mapToCodedBlockPatternValue(UInt32 codeNum, UInt32 chromaArrayType, Macroblock.MacroblockPartitionPredictionMode macroblockPartitionPredictionMode)           
		{
			
			if((chromaArrayType==1 || chromaArrayType==2) && (macroblockPartitionPredictionMode==Macroblock.MacroblockPartitionPredictionMode.Intra_4x4) || (macroblockPartitionPredictionMode==Macroblock.MacroblockPartitionPredictionMode.Intra_8x8))
				return chromaArratType1Or2_Intra4x4_Intra8x8[codeNum];
			else if((chromaArrayType==1 || chromaArrayType==2) && macroblockPartitionPredictionMode==Macroblock.MacroblockPartitionPredictionMode.Inter)
				return chromaArratType1Or2_Inter[codeNum];
			else if((chromaArrayType==0 || chromaArrayType==3) && (macroblockPartitionPredictionMode==Macroblock.MacroblockPartitionPredictionMode.Intra_4x4) || (macroblockPartitionPredictionMode==Macroblock.MacroblockPartitionPredictionMode.Intra_8x8))
				return chromaArratType0Or3_Intra4x4_Intra8x8[codeNum];
			else if((chromaArrayType==0 || chromaArrayType==3) && macroblockPartitionPredictionMode==Macroblock.MacroblockPartitionPredictionMode.Inter)
				return chromaArratType0Or3_Inter[codeNum];
			else
				throw new ArgumentException();
			return 0;	
			
		}
		
		static UInt32[] chromaArratType1Or2_Intra4x4_Intra8x8 =   {47, 31, 15,  0, 23, 27, 29, 30,  7, 11,
																13, 14, 39, 43, 45, 46, 16,  3,  5, 10,
																12, 19, 21, 26, 28, 35, 37, 42, 44,  1,
																 2,  4,  8, 17, 18, 20, 24,  6,  9, 22,
																25, 32, 33, 34, 36, 40, 38, 41};
		
		static UInt32[] chromaArratType1Or2_Inter			   =   { 0, 16,  1,  2,  4,  8, 32,  3,  5, 10,
																12, 15, 47,  7, 11, 13, 14,  6,  9, 31,
																35, 37, 42, 44, 33, 34, 36, 40, 39, 43,
																45, 46, 17, 18, 20, 24, 19, 21, 26, 28,
																23, 27, 29, 30, 22, 25, 38, 41};
		
		static UInt32[] chromaArratType0Or3_Intra4x4_Intra8x8 =   {15,  0,  7, 11, 13, 14,  3,  5, 10, 12,
																 1,  2,  4,  8,  6,  9};
		
		static UInt32[] chromaArratType0Or3_Inter             =   { 0,  1,  2,  4,  8,  3,  5, 10, 12, 15, 
																 7, 11, 13, 14,  6,  9};
		
		
	}
}
